package com.smartmail.receiving.pop3;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import javax.mail.FetchProfile;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.UIDFolder;
import javax.mail.internet.MimeMessage;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.smartmail.accounts.MailAccount;
import com.smartmail.mailing.MailMessage;
import com.smartmail.receiving.AbstractMessageHandler;
import com.smartmail.receiving.Receiving;
import com.smartmail.receiving.ReceivingRequestsHandler;
import com.smartmail.receiving.RetrievalService;
import com.smartmail.utility.MessageUtility;

public class POP3DownloadMsgsTask implements Runnable{
	
	/**
	 * Public constructor.
	 * 
	 * @param account - Mail Account from which messages to download will be downloaded
	 * @param context - Application context
	 */
	public POP3DownloadMsgsTask(MailAccount account, Context context){
		
		_mailAccount = account;
		_context = context;
	}

	/**
	 * 1. Get from POP3RetrievalThread information about messages to be downloaded
	 * 2. Connect to the POP3 mailbox
	 * 3. Retrieve from server Message object which will be downloaded on device
	 * 4. Download messages by POP3MessageHandler object
	 * 5. Send Intents about all messages that couldn't be downloaded from server
	 */
	@Override
	public void run() {
		
		Log.d(_logTag, "POP3DownloadMsgsTask : started, " + _mailAccount.getMailAddress());
		
		toDownloadList = RetrievalService.getRetrievalThread(_mailAccount).getMessagesToDownload();
		
		if( toDownloadList.isEmpty())
			return;
		
		try {
			
			messageHandler = new POP3MessageHandler(_context, _mailAccount);

			/**
			 * connect to the store and obtain inbox folder
			 */
			Properties props = new Properties();
			
			//set connection timeout to 7 secods
			props.put("mail.pop3.timeout", 7000);
			props.put("mail.pop3s.timeout", 7000);
			
			props.putAll(_mailAccount.getAccountProperties());

			Session session = Session.getInstance(props,
					_mailAccount.getPasswordAuthentication());
			Store store = session.getStore();

			store.connect(_mailAccount.getIncomingMailServerAddress(),
					_mailAccount.getAccountUsername(),
					_mailAccount.getAccountPassword());

			Folder folder = store.getDefaultFolder();
			folder = store.getFolder("INBOX");
			folder.open(Folder.READ_WRITE);

			Message messages[] = folder.getMessages();
			
			FetchProfile fp = new FetchProfile();
			fp.add(UIDFolder.FetchProfileItem.UID);
			folder.fetch(messages, fp);
			
			com.sun.mail.pop3.POP3Folder popFolder = (com.sun.mail.pop3.POP3Folder)folder;
			
			// fill array with UIDs of messages to be sent
			List<String> toDownloadMsgsUIDs = new ArrayList<String>();
			
			for(MailMessage m : toDownloadList){
				toDownloadMsgsUIDs.add(m.getMessageUID());
			}
			

			// find messages in inbox with same UID or non-UID specified
			List<Message> messagesPossibleToDownload = new ArrayList<Message>();
			for(Message m : messages){
				
				String uid = popFolder.getUID(m);
				if( uid == null || toDownloadMsgsUIDs.contains(uid))
					messagesPossibleToDownload.add(m);
			}
			
			Collections.reverse(messagesPossibleToDownload);
			//find messages with same RFC ID - it must be exactly messages to download
			for(Message m : messagesPossibleToDownload){
				
				// every message should be of Mime type
				if (m instanceof MimeMessage) {
					
					MimeMessage mimeMessage = (MimeMessage) m;
					String messageHash = MessageUtility.getHash(mimeMessage);
					
					MailMessage toDelete = null;
					for(MailMessage mailMessage : toDownloadList){
						
						if( mailMessage.getMessageHash().equals(messageHash)){
							
							messageHandler.download(mimeMessage);
							toDelete = mailMessage;
							break;
						}	
					}
					if(toDelete != null)
						toDownloadList.remove(toDelete);
	
				}
			}
			
			if( !toDownloadList.isEmpty() ){
				
				//TODO : send intent with information that such message is unobtainable in server
			}

			folder.close(false);
			store.close();

		} catch (MessagingException e) {

			for (StackTraceElement ste : e.getStackTrace()) {
				Log.d(RetrievalService._logTag, ste.toString());
			}

			Log.d(_logTag,
					"POP3RetrievalService : " + e.getMessage() + " "
							+ e.getCause());
		} catch (Exception e) {

			Log.d(_logTag,
					"POP3RetrievalService : exception other the MessaginException");
		} finally{
			
			/**
			 * all messages that user want to be downloaded but they couldn't be
			 * send intent to AccountMsgActivity with information that this messages are unavailable
			 */
			while( !toDownloadList.isEmpty() ){
				
				MailMessage message = toDownloadList.get(0);
				Intent intent = new Intent(Receiving.MESSAGE_UNAVAILABLE_INTENT);
				intent.putExtra(Receiving.MAIL_INFO_ACCOUNT_ID, _mailAccount.getAccountID());
				intent.putExtra(Receiving.MAIL_INFO_HASH, message.getMessageHash());
				_context.sendBroadcast(intent);
				
				ReceivingRequestsHandler.setState(_mailAccount, message, MailMessage._MESSAGE_NOT_DOWNLOADED);
				toDownloadList.remove(message);
				
			}
			
		}
		
	}
	
	/**
	 * Mail Account from which messages to download will be downloaded
	 */
	private MailAccount _mailAccount;
	
	/**
	 * logTag for logging purposes
	 */
	private static String _logTag = "com.smartmail.receiving.pop3";
	
	/**
	 * Application context
	 */
	private Context _context;
	
	/**
	 * List of messages to be downloaded from POP3 server
	 */
	private List<MailMessage> toDownloadList;
	
	/**
	 * POP3MessageHandler object to handle message to download
	 */
	private AbstractMessageHandler messageHandler;

}
